/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Control;
import Model.Shape;
import Model.Star;
import Model.Oval;
import Model.FillOval;
import Model.FillDiamond;
import Model.FillTriangle;
import Model.Hexagon;
import Model.FillHexagon;
import Model.FillStar;
import Model.FillRoundRectangular;
import Model.FillRectangular;
import Model.Line;
import Model.FillArrowUp;
import Model.FillArrowRight;
import Model.FillArrowDown;
import Model.FillArrowLeft;
import Model.Diamond;
import Model.Curve;
import Model.BlockColor;
import Model.ArrowUp;
import Model.ArrowLeft;
import Model.ArrowRight;
import Model.ArrowDown;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
/**
 *
 * @author PhucAnh
 */
 public class Control {
    int i=0;
    View view;
    LinkedList<Object> objs;
    LinkedList<Object> redo=new LinkedList<Object>();
    int nline=0;
    Point p;
    int kt=0;
    int x,y;
     public Control(View myview,LinkedList<Object> ll) {
         
        this.view = myview;
        this.objs=ll;
        this.view.addViewMouseListener(new MouseAdapter() {
             
            @Override
            public void mouseClicked(MouseEvent e)
            { 
                if(objs.size()>0&&( !((Shape)objs.getLast()).isContain(new Point(e.getX(),e.getY())))&& view.getIsMove()==true )
                view.setIsMove(false);
                 p=new Point(e.getX(),e.getY());
               if(view.getFillColor()&&inCanvas(p.x, p.y))
                {redo.clear();
                    BufferedImage temp = new BufferedImage(view.getWidthPaint(),view.getHeightPaint(),java.awt.image.BufferedImage.TYPE_INT_RGB);
                Graphics g = temp.getGraphics();
                view.jpnPaint.paint(g);
                g.dispose();
                
                    Point[] ll=new Point[view.jpnPaint.getHeight()*view.jpnPaint.getWidth()];
                int n1=0;
                    int getColor = ((BufferedImage)temp).getRGB(p.x, p.y);
                    LinkedList<Point> Q = new LinkedList<Point>();
                    if(inCanvas(p.x, p.y) && ((BufferedImage)temp).getRGB(p.x, p.y) == getColor && getColor != view.getColor().getRGB()) {
                        Q.addLast(p);
                        while(!Q.isEmpty()) {
                        Point n = Q.removeLast();
                    if(inCanvas(n.x, n.y) && ((BufferedImage)temp).getRGB(n.x, n.y) == getColor) {
                 ll[n1]=n;
                 n1++;
                    ((BufferedImage)temp).setRGB(n.x, n.y, view.getColor().getRGB());
                    ((BufferedImage)view.bufferImage).setRGB(n.x, n.y, view.getColor().getRGB());
                    Q.addLast(new Point(n.x-1, n.y));
                    Q.addLast(new Point(n.x+1, n.y));
                    Q.addLast(new Point(n.x, n.y+1));
                    Q.addLast(new Point(n.x, n.y-1));
                }
                        }
            }
                    Point[] ll1=new Point[n1];
               for(int i=0;i<n1;i++)
               {
                   ll1[i]=new Point();
                   ll1[i].x=ll[i].x;
                   ll1[i].y=ll[i].y;
               }
               ll=null;
               System.runFinalization();
                objs.addLast(new BlockColor(ll1,n1,view.getColor(),getColor));
                
               }
               else
                undo((BufferedImage)view.bufferImage);
//               {
//                   JFrame frame = new JFrame();
//                   NewClass a=new NewClass(lLine1,view);
//        frame.getContentPane().add(a);
//        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//        frame.setSize(1000,1000);
//        frame.setVisible(true);
//               }
//                view.repaint();
               
            }
            
            public void mouseReleased(MouseEvent e)
            {
                if(kt==1)
                   view.setIsMove(true);
                kt=0;
            }
           public void mousePressed(MouseEvent e) {
               if( objs.size() <= 0 || ( !((Shape)objs.getLast()).isContain(new Point(e.getX(),e.getY())) ) || view.getIsMove() ==false )
               view.setIsMove(false);
               
               p=new Point(e.getX(),e.getY());
             }
         });
        
        this.view.addViewMouseMotionListener(new MouseAdapter(){
            @Override
            public void mouseDragged(java.awt.event.MouseEvent e)
            {

                if(view.isIsEraser())
                    if(kt==0){redo.clear();
                        objs.add(new Curve(Color.WHITE,view.getBasicStroke()));kt=1;}
                            else
                        ((Curve)objs.getLast()).addPoint(new Point(e.getX(),e.getY()));
                else
                switch(view.getTypeShape())
                {
                    case "OVAL":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new Oval(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((Oval)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "LINE":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new Line(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((Line)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "RECTANGULAR":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new Rectangular(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((Rectangular)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "TRIANGLE":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new Triangle(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((Triangle)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "ARROWL":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new ArrowLeft(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((ArrowLeft)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "ARROWR":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new ArrowRight(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((ArrowRight)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "ARROWU":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new ArrowUp(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((ArrowUp)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "ARROWD":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new ArrowDown(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((ArrowDown)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "STAR":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new Star(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((Star)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "DIAMOND":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new Diamond(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((Diamond)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "HEXAGON":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new Hexagon(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((Hexagon)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "ROUNDRECTAGULAR":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new RoundRectangular(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((RoundRectangular)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLOVAL":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillOval(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillOval)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLRECTANGULAR":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillRectangular(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillRectangular)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLTRIANGLE":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillTriangle(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillTriangle)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLARROWL":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillArrowLeft(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillArrowLeft)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLARROWR":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillArrowRight(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillArrowRight)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLARROWU":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillArrowUp(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillArrowUp)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLARROWD":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillArrowDown(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillArrowDown)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLSTAR":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillStar(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillStar)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLDIAMOND":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillDiamond(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillDiamond)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLHEXAGON":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillHexagon(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillHexagon)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                    case "FILLROUNDRECTAGULAR":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new FillRoundRectangular(p,new Point(e.getX(),e.getY()),view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((FillRoundRectangular)objs.getLast()).setPoint2(new Point(e.getX(),e.getY()));
                        break;
                   case "CURVE":
                        if(view.getIsMove()==true){
                            ((Shape)objs.getLast()).toMove(e.getX()-p.getX(),e.getY()-p.getY());
                            p=new Point(e.getX(),e.getY());
                            break;
                        }
                        if(kt==0){redo.clear();
                        objs.add(new Curve(view.getColor(),view.getBasicStroke()));kt=1;}
                            else
                        ((Curve)objs.getLast()).addPoint(new Point(e.getX(),e.getY()));
                        break;
                   default:
                       break;
                }
                view.repaint();
            }
        });
        
    }
     
     public boolean inCanvas(int x,int y)
     {
         
         if(view.jpnPaint.getSize().height>y&&x>=0&&view.jpnPaint.getSize().width>x&&y>=0)
             return true;
             return false;
     }
     
     public void undo(BufferedImage a){
         if(objs.size()>0){
         Object tmp=objs.removeLast();
         ((Shape)tmp).undo(a);
         redo.addLast(tmp);
         }
     }
     
     public void redo(BufferedImage a){
         if(redo.size()>0){
         Object tmp = redo.removeLast();
//         ((Shape)tmp).redo(a);
         objs.addLast(tmp);
         }
     }
     
}
